﻿using Shop.Collect;
using Shop.ExtendService;
using Shop.LocalEvent;
using Shop.Model.DB;
using Shop.Model.Goods;
using Shop.RemoteModel.Goods.Model;
using Shop.RemoteModel.SpuGoods.Model;
using Shop.Service.Helper;
using Shop.Service.Interface;
using WeDonekRpc.Client;
using WeDonekRpc.Helper;
using WeDonekRpc.Model;

namespace Shop.Service.lmpl
{
    internal class GoodsService : IGoodsService
    {
        private readonly IGoodsCollect _Service;
        private readonly IFileService _File;
        private readonly IGoodsSkuCollect _Sku;
        private readonly ICategoryCollect _Category;
        public GoodsService ( IGoodsCollect service,
            IFileService file,
            IGoodsSkuCollect sku,
            ICategoryCollect category )
        {
            _Sku = sku;
            this._File = file;
            this._Service = service;
            this._Category = category;
        }
        public SpuDatum[] Gets( TopGetArg arg )
        {
            if ( arg.SortName.IsNull() )
            {
                arg.SortName = "Id";
            }
            return _Service.GetTops<SpuDatum>(arg);
        }
        public long Add ( GoodsSet arg )
        {
            GoodsSetArg set = arg.ConvertMap<GoodsSet, GoodsSetArg>();
            this._InitCategory(set);
            long id = this._Service.Add(set);
            if ( !arg.FileId.IsNull() )
            {
                this._File.Save(arg.FileId, id);
            }
            return id;
        }
        private void _InitCategory ( GoodsSetArg set )
        {
            DBCategory category = this._Category.Get(set.CategoryId);
            if ( !category.IsEnable )
            {
                throw new ErrorException("shop.goods.category.no.enable");
            }
            if ( category.Lvl == 1 )
            {
                set.MainCategoryId = category.Id;
            }
            else
            {
                long[] parentId = category.LevelCode.Substring(1, category.LevelCode.Length - 1).SplitToLong('|');
                if ( category.Lvl == 3 )
                {
                    set.MainCategoryId = parentId[0];
                    set.TwoCategoryId = parentId[1];
                    set.ThreeCategoryId = category.Id;
                }
                else if ( category.Lvl == 2 )
                {
                    set.MainCategoryId = parentId[0];
                    set.TwoCategoryId = category.Id;
                }
                else
                {
                    set.MainCategoryId = parentId[0];
                    set.TwoCategoryId = parentId[1];
                    set.ThreeCategoryId = parentId[2];
                }
            }
        }
        public void Delete ( long id )
        {
            DBGoods goods = this._Service.Get(id);
            this._Service.Delete(goods);
        }

        public GoodsDatum GetDatum ( long id )
        {
            GoodsDatumDto dto = this._Service.Get<GoodsDatumDto>(id);
            return dto.ConvertMap<GoodsDatumDto, GoodsDatum>();
        }
        public GoodsDto[] Gets ( long[] ids )
        {
            GoodsData[] list = this._Service.Gets<GoodsData>(ids);
            return this._Format(list);
        }
        private GoodsDto[] _Format ( GoodsData[] list )
        {
            GoodsDto[] dtos = list.ConvertMap<GoodsData, GoodsDto>();
            Dictionary<long, string> names = this._Category.GetFullNames(dtos.Distinct(c => c.CategoryId));
            dtos.ForEach(c =>
            {
                c.CategoryName = names.GetValueOrDefault(c.CategoryId);
            });
            return dtos;
        }
        public PagingResult<GoodsDto> Query ( GoodsQueryParam query, IBasicPage paging )
        {
            GoodsQuery param = query.ConvertMap<GoodsQueryParam, GoodsQuery>();
            GoodsData[] list = this._Service.Query<GoodsData>(param, paging, out int count);
            if ( list.IsNull() )
            {
                return new PagingResult<GoodsDto>();
            }
            GoodsDto[] dtos = this._Format(list);
            return new PagingResult<GoodsDto>(dtos, count);
        }
        public void Public ( long id, long opUserId, Dictionary<long, int> stock )
        {
            DBGoods goods = this._Service.Get(id);
            decimal price = _Sku.GetMinPrice(stock.Keys.ToArray());
            if ( this._Service.Public(goods, (short)stock.Count, price))
            {
                new GoodsPublicEvent
                {
                    Goods = goods,
                    Stock = stock,
                    OpUserId = opUserId
                }.AsyncPublic();
            }
        }

        public void OffShelf ( long id )
        {
            DBGoods goods = this._Service.Get(id);
            this._Service.OffShelf(goods);
        }
        public bool Set ( long id, GoodsSet arg )
        {
            DBGoods goods = this._Service.Get(id);
            GoodsSetArg set = arg.ConvertMap<GoodsSet, GoodsSetArg>();
            if ( set.CategoryId != goods.CategoryId )
            {
                this._InitCategory(set);
            }
            else
            {
                set.MainCategoryId = goods.MainCategoryId;
                set.ThreeCategoryId = goods.ThreeCategoryId;
                set.TwoCategoryId = goods.TwoCategoryId;
            }
            string[] uris = goods.ServerShow.Convert<GoodsServeShow, string>(a => !a.ImgSrc.IsNull(), c => c.ImgSrc);
            if ( goods.MainImg.IsNotNull() )
            {
                uris = uris.Add(goods.MainImg);
            }
            if ( this._Service.Set(goods, set) )
            {
                this._File.Sync(arg.FileId, id, uris);
                return true;
            }
            return false;
        }
    }
}
